package sshutil

import (
	"fmt"
	"io"
	"os"
	"path/filepath"

	"golang.org/x/crypto/ssh"
)

// NewSession 建立 SSH 会话
func NewSession(host string, port int, user, password string) (*ssh.Client, *ssh.Session, error) {
	cfg := &ssh.ClientConfig{
		User:            user,
		Auth:            []ssh.AuthMethod{ssh.Password(password)},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 仅示例，生产请校验
	}
	addr := fmt.Sprintf("%s:%d", host, port)
	client, err := ssh.Dial("tcp", addr, cfg)
	if err != nil {
		return nil, nil, err
	}
	session, err := client.NewSession()
	if err != nil {
		client.Close()
		return nil, nil, err
	}
	return client, session, nil
}

// RunRemote 在远端执行一条命令
func RunRemote(client *ssh.Client, cmd string) error {
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	return session.Run(cmd)
}

// UploadFile 通过 SCP 上传单个文件
func UploadFile(client *ssh.Client, local, remote string) error {
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()

	// 打开本地文件
	src, err := os.Open(local)
	if err != nil {
		return err
	}
	defer src.Close()

	// 获取文件信息
	fi, err := src.Stat()
	if err != nil {
		return err
	}

	// 保证远端目录存在
	dir := filepath.Dir(remote)
	cmd := fmt.Sprintf("mkdir -p %q", dir)
	if err := RunRemote(client, cmd); err != nil {
		return err
	}

	// 启动 scp
	go func() {
		w, _ := session.StdinPipe()
		defer w.Close()
		fmt.Fprintf(w, "C0644 %d %s\n", fi.Size(), filepath.Base(remote))
		io.Copy(w, src)
		fmt.Fprint(w, "\x00")
	}()

	return session.Run("/usr/bin/scp -t " + remote)
}
